/*global pi */

/**
 * 四元数 quaternion
 * {w, x, y, z}
 */

pi.mod.define('pi.math.quat', function (pi) {
	"use strict";
	var module = {},
		tmpV1 = pi.math.vec3.create(),
		tmpV2 = pi.math.vec3.create();

	// 零四元数
	module.ZERO = {
		w: 0.0,
		x: 0.0,
		y: 0.0,
		z: 0.0
	};

	// 单位四元数
	module.UNIT = {
		w: 1.0,
		x: 0.0,
		y: 0.0,
		z: 0.0
	};

	// 创建
	module.create = function (wVal, xVal, yVal, zVal) {
		return {
			w: wVal || 1.0,
			x: xVal || 0.0,
			y: yVal || 0.0,
			z: zVal || 0.0
		};
	};

	// 设置
	module.set = function (dst, wVal, xVal, yVal, zVal) {
		dst.w = wVal || 0.0;
		dst.x = xVal || 0.0;
		dst.y = yVal || 0.0;
		dst.z = zVal || 0.0;
	};

	// 拷贝
	module.copy = function (dst, src) {
		dst.w = src.w;
		dst.x = src.x;
		dst.y = src.y;
		dst.z = src.z;
	};

	// 是否相等
	module.isEqual = function (q1, q2) {
		return Math.abs(q1.w - q2.w) < Number.MIN_VALUE && Math.abs(q1.x - q2.x) < Number.MIN_VALUE && Math.abs(q1.y - q2.y) < Number.MIN_VALUE && Math.abs(q1.z - q2.z) < Number.MIN_VALUE;
	};

	// 加法
	module.add = function (dst, q1, q2) {
		dst.w = q1.w + q2.w;
		dst.x = q1.x + q2.x;
		dst.y = q1.y + q2.y;
		dst.z = q1.z + q2.z;
	};

	// 减法
	module.sub = function (dst, q1, q2) {
		dst.w = q1.w - q2.w;
		dst.x = q1.x - q2.x;
		dst.y = q1.y - q2.y;
		dst.z = q1.z - q2.z;
	};

	// 数乘
	module.scale = function (dst, src, num) {
		dst.w = src.w * num;
		dst.x = src.x * num;
		dst.y = src.y * num;
		dst.z = src.z * num;
	};

	//点积
	module.dot = function (q1, q2) {
		return q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
	};

	// 长度的平方
	module.lengthSq = function (q) {
		return q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z;
	};

	// 长度
	module.length = function (q) {
		return Math.sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z);
	};

	// 共轭(conjugate)四元数: {w, -x, -y, -z}
	module.conj = function (dst, src) {
		dst.w = src.w;
		dst.x = -src.x;
		dst.y = -src.y;
		dst.z = -src.z;
	};

	// 乘法
	module.mul = function (dst, q1, q2) {
		var wVal = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
			xVal = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
			yVal = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,
			zVal = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
		dst.w = wVal;
		dst.x = xVal;
		dst.y = yVal;
		dst.z = zVal;
	};

	// 单位化
	module.normalize = function (dst, src) {
		var len = src.w * src.w + src.x * src.x + src.y * src.y + src.z * src.z;
		if (len === 0) {
			dst.w = dst.x = dst.y = dst.z = 0.0;
		} else {
			len = 1.0 / Math.sqrt(len);
			dst.w = src.w * len;
			dst.x = src.x * len;
			dst.y = src.y * len;
			dst.z = src.z * len;
		}
	};

	// 逆
	module.inverse = function (dst, src) {
		var len = src.x * src.x + src.y * src.y + src.z * src.z;
		if (len === 0) {
			dst.w = dst.x = dst.y = dst.z = 0.0;
		} else {
			len = 1.0 / Math.sqrt(len);
			dst.w = src.w * len;
			dst.x = -src.x * len;
			dst.y = -src.y * len;
			dst.z = -src.z * len;
		}
	};

	// 从旋转矩阵转换为四元数
	module.fromMat = function (m) {
		pi.log("quat.from isn't implement");
	};

	/**
	 * 从轴和弧度角构建四元数
	 * 注意：axis必须是单位向量
	 */
	module.fromAxisAngle = function (dst, axis, rad) {
		var halfAng = 0.5 * rad,
			s = Math.sin(halfAng);
		dst.w = Math.cos(halfAng);
		dst.x = s * axis.x;
		dst.y = s * axis.y;
		dst.z = s * axis.z;
	};

	// 从四元数取出轴和弧度角: 返回：{axis: 轴, angle: 弧度表示的角}
	module.getAxisAngle = function (q) {
		var r, f = q.x * q.x + q.y * q.y + q.z * q.z;
		if (Math.abs(f) < Number.MIN_VALUE) {
			// 角度是2PI的整数倍，任何轴都可以
			r = {
				angle: 0.0,
				axis: pi.math.vec3.create(1.0, 0.0, 0.0)
			};
		} else {
			f = 1.0 / Math.sqrt(f);
			r = {
				angle: 2.0 * Math.acos(q.w),
				axis: pi.math.vec3.create(f * q.x, f * q.y, f * q.z)
			};
		}
		return r;
	};

	// 旋转向量
	module.rotateVec = function (dst, q, src) {
		var qVec = pi.math.vec3.create(q.x, q.y, q.z);
		pi.math.vec3.cross(tmpV1, qVec, src);
		pi.math.vec3.cross(tmpV2, qVec, tmpV1);

		pi.math.vec3.scale(tmpV1, tmpV1, 2.0 * q.w);
		pi.math.vec3.scale(tmpV2, tmpV2, 2.0);

		pi.math.vec3.add(dst, src, tmpV1);
		pi.math.vec3.add(dst, dst, tmpV2);
	};

	// 球面线性插值：isShortest表示：是否选择最短弧
	module.slerp = function (dst, qFrom, qTo, frac, isShortest) {
		var fSin, fRadAngle, fInvSin, fCoeff0, fCoeff1, temp2 = module.create(),
			temp1 = module.create(),
			fCos = module.dot(qFrom, qTo);
		if (fCos < 0.0 && isShortest) {
			fCos = -fCos;
			module.set(temp1, -qTo.w, -qTo.x, -qTo.y, -qTo.z);
		} else {
			module.copy(temp1, qTo);
		}

		if (Math.abs(fCos) >= 1.0) {
			module.scale(temp2, qFrom, 1.0 - frac);
			module.scale(temp1, temp1, frac);
			module.add(temp2, temp2, temp1);
			module.normalize(dst, temp2);
		} else {
			fSin = Math.sqrt(1.0 - fCos * fCos);
			fRadAngle = Math.atan2(fSin, fCos);
			fInvSin = 1.0 / fSin;
			fCoeff0 = fInvSin * Math.sin((1.0 - frac) * fRadAngle);
			fCoeff1 = fInvSin * Math.sin(frac * fRadAngle);
			module.scale(temp2, qFrom, fCoeff0);
			module.scale(temp1, temp1, fCoeff1);
			module.add(dst, temp2, temp1);
		}
	};

	// 线性插值：isShortest表示：是否选择最短弧
	module.lerp = function (dst, qFrom, qTo, frac, isShortest) {
		var q = qTo,
			f = module.dot(qFrom, qTo);
		if (f < 0.0 && isShortest) {
			q = {
				w: -qTo.w,
				x: -qTo.x,
				y: -qTo.y,
				z: -qTo.z
			};
		}

		// dst = from + frac * (to - from)
		dst.w = qFrom.w + frac * (q.w - qFrom.w);
		dst.x = qFrom.x + frac * (q.x - qFrom.x);
		dst.y = qFrom.y + frac * (q.y - qFrom.y);
		dst.z = qFrom.z + frac * (q.z - qFrom.z);

		module.normalize(dst, dst);
	};

	// 构造from转到to的四元数，dst = Rotate(from, to)
	module.rotateTo = function (vFrom, vTo) {
		pi.log("quat.rotateTo isn't implement");
	};

	// 取局部的x轴
	module.xAixs = function (dst, q) {
		var fTy = 2.0 * q.y,
			fTz = 2.0 * q.z,
			fTwy = fTy * q.w,
			fTwz = fTz * q.w,
			fTxy = fTy * q.x,
			fTxz = fTz * q.x,
			fTyy = fTy * q.y,
			fTzz = fTz * q.z;
		dst.x = 1.0 - (fTyy + fTzz);
		dst.y = fTxy + fTwz;
		dst.z = fTxz - fTwy;
	};

	// 取局部的y轴
	module.yAixs = function (dst, q) {
		var fTx = 2.0 * q.x,
			fTy = 2.0 * q.y,
			fTz = 2.0 * q.z,
			fTwx = fTx * q.w,
			fTwz = fTz * q.w,
			fTxx = fTx * q.x,
			fTxy = fTy * q.x,
			fTyz = fTz * q.y,
			fTzz = fTz * q.z;
		dst.x = fTxy - fTwz;
		dst.y = 1.0 - (fTxx + fTzz);
		dst.z = fTyz + fTwx;
	};

	// 取局部的z轴
	module.zAixs = function (dst, q) {
		var fTx = 2.0 * q.x,
			fTy = 2.0 * q.y,
			fTz = 2.0 * q.z,
			fTwx = fTx * q.w,
			fTwy = fTy * q.w,
			fTxx = fTx * q.x,
			fTxz = fTz * q.x,
			fTyy = fTy * q.y,
			fTyz = fTz * q.y;
		dst.x = fTxz + fTwy;
		dst.y = fTyz - fTwx;
		dst.z = 1.0 - (fTxx + fTyy);
	};

	// 取绕z轴转动的弧度 */
	module.rollAngle = function (q) {
		var fTy = 2.0 * q.y,
			fTz = 2.0 * q.z,
			fTwz = fTz * q.w,
			fTxy = fTy * q.x,
			fTyy = fTy * q.y,
			fTzz = fTz * q.z;
		return Math.atan2(fTxy + fTwz, 1.0 - (fTyy + fTzz));
	};

	// 取绕X轴转动的弧度 */
	module.pitchAngle = function (q) {
		var fTx = 2.0 * q.x,
			fTz = 2.0 * q.z,
			fTwx = fTx * q.w,
			fTxx = fTx * q.x,
			fTyz = fTz * q.y,
			fTzz = fTz * q.z;
		return Math.atan2(fTyz + fTwx, 1.0 - (fTxx + fTzz));
	};

	// 取绕y轴转动的弧度 */
	module.yawAngle = function (q) {
		var fTx = 2.0 * q.x,
			fTy = 2.0 * q.y,
			fTz = 2.0 * q.z,
			fTwy = fTy * q.w,
			fTxx = fTx * q.x,
			fTxz = fTz * q.x,
			fTyy = fTy * q.y;
		return Math.atan2(fTxz + fTwy, 1.0 - (fTxx + fTyy));
	};

	return module;
});